{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Run the \"Real-time Credit Scoring\" tutorial"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "We'll use the following tutorial as a demonstration.\n",
    "\n",
    "https://github.com/feast-dev/feast-credit-score-local-tutorial/tree/598a270353d8a83b37535f849a0fa000a07be8b5"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Check the init container to ensure the repo was successfully cloned with git."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Creating feast repository...\n",
      "git clone https://github.com/feast-dev/feast-credit-score-local-tutorial /feast-data/credit_scoring_local && cd /feast-data/credit_scoring_local && git checkout 598a270\n",
      "Cloning into '/feast-data/credit_scoring_local'...\n",
      "Updating files: 100% (25/25), done.\n",
      "Note: switching to '598a270'.\n",
      "\n",
      "You are in 'detached HEAD' state. You can look around, make experimental\n",
      "changes and commit them, and you can discard any commits you make in this\n",
      "state without impacting any branches by switching back to a branch.\n",
      "\n",
      "If you want to create a new branch to retain commits you create, you may\n",
      "do so (now or later) by using -c with the switch command. Example:\n",
      "\n",
      "  git switch -c <new-branch-name>\n",
      "\n",
      "Or undo this operation with:\n",
      "\n",
      "  git switch -\n",
      "\n",
      "Turn off this advice by setting config variable advice.detachedHead to false\n",
      "\n",
      "HEAD is now at 598a270 set streamlit version to 1.42.0 (#8)\n",
      "Feast repo creation complete\n"
     ]
    }
   ],
   "source": [
    "!kubectl logs -f deploy/feast-example -c feast-init"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Verify the client `feature_store.yaml`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "project: credit_scoring_local\n",
      "provider: local\n",
      "offline_store:\n",
      "    type: duckdb\n",
      "online_store:\n",
      "    type: redis\n",
      "    connection_string: redis.feast.svc.cluster.local:6379\n",
      "registry:\n",
      "    path: postgresql+psycopg://${POSTGRES_USER}:${POSTGRES_PASSWORD}@postgres.feast.svc.cluster.local:5432/${POSTGRES_DB}\n",
      "    registry_type: sql\n",
      "    cache_ttl_seconds: 60\n",
      "    sqlalchemy_config_kwargs:\n",
      "        echo: false\n",
      "        pool_pre_ping: true\n",
      "auth:\n",
      "    type: no_auth\n",
      "entity_key_serialization_version: 3\n"
     ]
    }
   ],
   "source": [
    "!kubectl exec deploy/feast-example -itc online -- cat feature_store.yaml"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Apply the tutorial feature store definitions"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Update the feature store definitions for the tutorial and load data from feature views into the online store, beginning from either the previous materialize or materialize-incremental end date, or the beginning of time.\n",
    "\n",
    "We'll do this by using the CronJob created by the operator which, by default, will execute the following commands when run -\n",
    " - feast apply\n",
    " - feast materialize-incremental $(date -u +'%Y-%m-%dT%H:%M:%S')\n",
    "\n",
    "Before we run the Job, let's ensure our FeatureStore CR is configured accordingly."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[\"feast apply\",\"feast materialize-incremental $(date -u +'%Y-%m-%dT%H:%M:%S')\"]"
     ]
    }
   ],
   "source": [
    "!kubectl get feast/example -o jsonpath='{.status.applied.cronJob.containerConfigs.commands}'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now let's run a Job from the existing CronJob, wait for its completion, and then check the logs."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "job.batch/feast-example-apply created\n",
      "job.batch/feast-example-apply condition met\n",
      "Defaulted container \"online\" out of: online, feast-init (init)\n",
      "No project found in the repository. Using project name credit_scoring_local defined in feature_store.yaml\n",
      "Applying changes for project credit_scoring_local\n",
      "/opt/app-root/src/sdk/python/feast/feature_store.py:581: RuntimeWarning: On demand feature view is an experimental feature. This API is stable, but the functionality does not scale well for offline retrieval\n",
      "  warnings.warn(\n",
      "Deploying infrastructure for zipcode_features\n",
      "Deploying infrastructure for credit_history\n",
      "Defaulted container \"online\" out of: online, feast-init (init)\n",
      "Materializing \u001b[1m\u001b[32m2\u001b[0m feature views to \u001b[1m\u001b[32m2025-04-04 16:25:12+00:00\u001b[0m into the \u001b[1m\u001b[32mredis\u001b[0m online store.\n",
      "\n",
      "\u001b[1m\u001b[32mcredit_history\u001b[0m from \u001b[1m\u001b[32m2025-04-04 15:01:55+00:00\u001b[0m to \u001b[1m\u001b[32m2025-04-04 16:25:12+00:00\u001b[0m:\n",
      "0it [00:00, ?it/s]\n",
      "\u001b[1m\u001b[32mzipcode_features\u001b[0m from \u001b[1m\u001b[32m2025-04-04 15:01:55+00:00\u001b[0m to \u001b[1m\u001b[32m2025-04-04 16:25:12+00:00\u001b[0m:\n",
      "0it [00:00, ?it/s]\n"
     ]
    }
   ],
   "source": [
    "!kubectl create job --from=cronjob/feast-example feast-example-apply\n",
    "!kubectl wait --for=condition=complete --timeout=8m job/feast-example-apply\n",
    "!kubectl logs job/feast-example-apply --all-containers=true"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Execute feast commands inside the client Pod"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "List the registered feast projects, feature views, & entities."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "NAME                  DESCRIPTION    TAGS    OWNER\n",
      "credit_scoring_local                 {}\n",
      "NAME              ENTITIES     TYPE\n",
      "credit_history    {'dob_ssn'}  FeatureView\n",
      "zipcode_features  {'zipcode'}  FeatureView\n",
      "total_debt_calc   {'dob_ssn'}  OnDemandFeatureView\n",
      "NAME     DESCRIPTION                                                   TYPE\n",
      "zipcode                                                                ValueType.INT64\n",
      "dob_ssn  Date of birth and last four digits of social security number  ValueType.STRING\n"
     ]
    }
   ],
   "source": [
    "!kubectl exec deploy/feast-example -itc online -- feast projects list\n",
    "!kubectl exec deploy/feast-example -itc online -- feast feature-views list\n",
    "!kubectl exec deploy/feast-example -itc online -- feast entities list"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Train and test the model"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Install the required packages, then train and test the model.\n",
    "\n",
    "We'll do this by leveraging the same Operator created CronJob. We'll modify it to run the following commands for us -\n",
    " - pip install -r ../requirements.txt\n",
    " - cd ../ && python run.py"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "featurestore.feast.dev/example patched\n"
     ]
    }
   ],
   "source": [
    "!kubectl patch feast/example --patch '{\"spec\":{\"cronJob\":{\"containerConfigs\":{\"commands\":[\"pip install -r ../requirements.txt\",\"cd ../ && python run.py\"]}}}}' --type=merge"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Again, before we run the Job, let's ensure our FeatureStore CR is configured accordingly."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[\"pip install -r ../requirements.txt\",\"cd ../ \\u0026\\u0026 python run.py\"]"
     ]
    }
   ],
   "source": [
    "!kubectl get feast/example -o jsonpath='{.status.applied.cronJob.containerConfigs.commands}'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now let's run another Job from the modified CronJob, wait for its completion, and then check the logs.\n",
    "The completed Job logs should show all necessary python installs and end with \"Loan rejected!\"."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "job.batch/feast-example-demo created\n",
      "job.batch/feast-example-demo condition met\n",
      "Defaulted container \"online\" out of: online, feast-init (init)\n",
      "Collecting streamlit==1.42.0 (from -r ../requirements.txt (line 1))\n",
      "  Obtaining dependency information for streamlit==1.42.0 from https://files.pythonhosted.org/packages/ad/dc/69068179e09488d0833a970d06e8bf40e35669a7bddb8a3caadc13b7dff4/streamlit-1.42.0-py2.py3-none-any.whl.metadata\n",
      "  Downloading streamlit-1.42.0-py2.py3-none-any.whl.metadata (8.9 kB)\n",
      "Collecting shap (from -r ../requirements.txt (line 2))\n",
      "  Obtaining dependency information for shap from https://files.pythonhosted.org/packages/2a/c2/aa91dbb9cc8eee20f5bd245fd8fe27fc45fba786c3e04d35ed510f111b17/shap-0.47.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata\n",
      "  Downloading shap-0.47.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (25 kB)\n",
      "Requirement already satisfied: pandas in /opt/app-root/lib64/python3.11/site-packages (from -r ../requirements.txt (line 3)) (2.2.3)\n",
      "Collecting scikit-learn (from -r ../requirements.txt (line 4))\n",
      "  Obtaining dependency information for scikit-learn from https://files.pythonhosted.org/packages/a8/f3/62fc9a5a659bb58a03cdd7e258956a5824bdc9b4bb3c5d932f55880be569/scikit_learn-1.6.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata\n",
      "  Downloading scikit_learn-1.6.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (18 kB)\n",
      "Collecting matplotlib (from -r ../requirements.txt (line 5))\n",
      "  Obtaining dependency information for matplotlib from https://files.pythonhosted.org/packages/40/b8/53fa08a5eaf78d3a7213fd6da1feec4bae14a81d9805e567013811ff0e85/matplotlib-3.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata\n",
      "  Downloading matplotlib-3.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (11 kB)\n",
      "Collecting altair<6,>=4.0 (from streamlit==1.42.0->-r ../requirements.txt (line 1))\n",
      "  Obtaining dependency information for altair<6,>=4.0 from https://files.pythonhosted.org/packages/aa/f3/0b6ced594e51cc95d8c1fc1640d3623770d01e4969d29c0bd09945fafefa/altair-5.5.0-py3-none-any.whl.metadata\n",
      "  Downloading altair-5.5.0-py3-none-any.whl.metadata (11 kB)\n",
      "Collecting blinker<2,>=1.0.0 (from streamlit==1.42.0->-r ../requirements.txt (line 1))\n",
      "  Obtaining dependency information for blinker<2,>=1.0.0 from https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl.metadata\n",
      "  Downloading blinker-1.9.0-py3-none-any.whl.metadata (1.6 kB)\n",
      "Requirement already satisfied: cachetools<6,>=4.0 in /opt/app-root/lib64/python3.11/site-packages (from streamlit==1.42.0->-r ../requirements.txt (line 1)) (5.5.2)\n",
      "Requirement already satisfied: click<9,>=7.0 in /opt/app-root/lib64/python3.11/site-packages (from streamlit==1.42.0->-r ../requirements.txt (line 1)) (8.1.8)\n",
      "Requirement already satisfied: numpy<3,>=1.23 in /opt/app-root/lib64/python3.11/site-packages (from streamlit==1.42.0->-r ../requirements.txt (line 1)) (1.26.4)\n",
      "Requirement already satisfied: packaging<25,>=20 in /opt/app-root/lib64/python3.11/site-packages (from streamlit==1.42.0->-r ../requirements.txt (line 1)) (24.2)\n",
      "Collecting pillow<12,>=7.1.0 (from streamlit==1.42.0->-r ../requirements.txt (line 1))\n",
      "  Obtaining dependency information for pillow<12,>=7.1.0 from https://files.pythonhosted.org/packages/48/a4/fbfe9d5581d7b111b28f1d8c2762dee92e9821bb209af9fa83c940e507a0/pillow-11.1.0-cp311-cp311-manylinux_2_28_x86_64.whl.metadata\n",
      "  Downloading pillow-11.1.0-cp311-cp311-manylinux_2_28_x86_64.whl.metadata (9.1 kB)\n",
      "Requirement already satisfied: protobuf<6,>=3.20 in /opt/app-root/lib64/python3.11/site-packages (from streamlit==1.42.0->-r ../requirements.txt (line 1)) (5.29.4)\n",
      "Requirement already satisfied: pyarrow>=7.0 in /opt/app-root/lib64/python3.11/site-packages (from streamlit==1.42.0->-r ../requirements.txt (line 1)) (17.0.0)\n",
      "Requirement already satisfied: requests<3,>=2.27 in /opt/app-root/lib64/python3.11/site-packages (from streamlit==1.42.0->-r ../requirements.txt (line 1)) (2.32.3)\n",
      "Requirement already satisfied: rich<14,>=10.14.0 in /opt/app-root/lib64/python3.11/site-packages (from streamlit==1.42.0->-r ../requirements.txt (line 1)) (13.9.4)\n",
      "Requirement already satisfied: tenacity<10,>=8.1.0 in /opt/app-root/lib64/python3.11/site-packages (from streamlit==1.42.0->-r ../requirements.txt (line 1)) (8.5.0)\n",
      "Requirement already satisfied: toml<2,>=0.10.1 in /opt/app-root/lib64/python3.11/site-packages (from streamlit==1.42.0->-r ../requirements.txt (line 1)) (0.10.2)\n",
      "Requirement already satisfied: typing-extensions<5,>=4.4.0 in /opt/app-root/lib64/python3.11/site-packages (from streamlit==1.42.0->-r ../requirements.txt (line 1)) (4.13.0)\n",
      "Collecting watchdog<7,>=2.1.5 (from streamlit==1.42.0->-r ../requirements.txt (line 1))\n",
      "  Obtaining dependency information for watchdog<7,>=2.1.5 from https://files.pythonhosted.org/packages/b5/e8/dbf020b4d98251a9860752a094d09a65e1b436ad181faf929983f697048f/watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl.metadata\n",
      "  Downloading watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl.metadata (44 kB)\n",
      "     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 44.3/44.3 kB 11.2 MB/s eta 0:00:00\n",
      "Collecting gitpython!=3.1.19,<4,>=3.0.7 (from streamlit==1.42.0->-r ../requirements.txt (line 1))\n",
      "  Obtaining dependency information for gitpython!=3.1.19,<4,>=3.0.7 from https://files.pythonhosted.org/packages/1d/9a/4114a9057db2f1462d5c8f8390ab7383925fe1ac012eaa42402ad65c2963/GitPython-3.1.44-py3-none-any.whl.metadata\n",
      "  Downloading GitPython-3.1.44-py3-none-any.whl.metadata (13 kB)\n",
      "Collecting pydeck<1,>=0.8.0b4 (from streamlit==1.42.0->-r ../requirements.txt (line 1))\n",
      "  Obtaining dependency information for pydeck<1,>=0.8.0b4 from https://files.pythonhosted.org/packages/ab/4c/b888e6cf58bd9db9c93f40d1c6be8283ff49d88919231afe93a6bcf61626/pydeck-0.9.1-py2.py3-none-any.whl.metadata\n",
      "  Downloading pydeck-0.9.1-py2.py3-none-any.whl.metadata (4.1 kB)\n",
      "Collecting tornado<7,>=6.0.3 (from streamlit==1.42.0->-r ../requirements.txt (line 1))\n",
      "  Obtaining dependency information for tornado<7,>=6.0.3 from https://files.pythonhosted.org/packages/22/55/b78a464de78051a30599ceb6983b01d8f732e6f69bf37b4ed07f642ac0fc/tornado-6.4.2-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata\n",
      "  Downloading tornado-6.4.2-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (2.5 kB)\n",
      "Collecting scipy (from shap->-r ../requirements.txt (line 2))\n",
      "  Obtaining dependency information for scipy from https://files.pythonhosted.org/packages/32/ea/564bacc26b676c06a00266a3f25fdfe91a9d9a2532ccea7ce6dd394541bc/scipy-1.15.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata\n",
      "  Downloading scipy-1.15.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (61 kB)\n",
      "     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 62.0/62.0 kB 7.6 MB/s eta 0:00:00\n",
      "Requirement already satisfied: tqdm>=4.27.0 in /opt/app-root/lib64/python3.11/site-packages (from shap->-r ../requirements.txt (line 2)) (4.67.1)\n",
      "Collecting slicer==0.0.8 (from shap->-r ../requirements.txt (line 2))\n",
      "  Obtaining dependency information for slicer==0.0.8 from https://files.pythonhosted.org/packages/63/81/9ef641ff4e12cbcca30e54e72fb0951a2ba195d0cda0ba4100e532d929db/slicer-0.0.8-py3-none-any.whl.metadata\n",
      "  Downloading slicer-0.0.8-py3-none-any.whl.metadata (4.0 kB)\n",
      "Collecting numba>=0.54 (from shap->-r ../requirements.txt (line 2))\n",
      "  Obtaining dependency information for numba>=0.54 from https://files.pythonhosted.org/packages/14/91/18b9f64b34ff318a14d072251480547f89ebfb864b2b7168e5dc5f64f502/numba-0.61.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl.metadata\n",
      "  Downloading numba-0.61.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl.metadata (2.8 kB)\n",
      "Requirement already satisfied: cloudpickle in /opt/app-root/lib64/python3.11/site-packages (from shap->-r ../requirements.txt (line 2)) (3.1.1)\n",
      "Requirement already satisfied: python-dateutil>=2.8.2 in /opt/app-root/lib64/python3.11/site-packages (from pandas->-r ../requirements.txt (line 3)) (2.9.0.post0)\n",
      "Requirement already satisfied: pytz>=2020.1 in /opt/app-root/lib64/python3.11/site-packages (from pandas->-r ../requirements.txt (line 3)) (2025.2)\n",
      "Requirement already satisfied: tzdata>=2022.7 in /opt/app-root/lib64/python3.11/site-packages (from pandas->-r ../requirements.txt (line 3)) (2025.2)\n",
      "Collecting joblib>=1.2.0 (from scikit-learn->-r ../requirements.txt (line 4))\n",
      "  Obtaining dependency information for joblib>=1.2.0 from https://files.pythonhosted.org/packages/91/29/df4b9b42f2be0b623cbd5e2140cafcaa2bef0759a00b7b70104dcfe2fb51/joblib-1.4.2-py3-none-any.whl.metadata\n",
      "  Downloading joblib-1.4.2-py3-none-any.whl.metadata (5.4 kB)\n",
      "Collecting threadpoolctl>=3.1.0 (from scikit-learn->-r ../requirements.txt (line 4))\n",
      "  Obtaining dependency information for threadpoolctl>=3.1.0 from https://files.pythonhosted.org/packages/32/d5/f9a850d79b0851d1d4ef6456097579a9005b31fea68726a4ae5f2d82ddd9/threadpoolctl-3.6.0-py3-none-any.whl.metadata\n",
      "  Downloading threadpoolctl-3.6.0-py3-none-any.whl.metadata (13 kB)\n",
      "Collecting contourpy>=1.0.1 (from matplotlib->-r ../requirements.txt (line 5))\n",
      "  Obtaining dependency information for contourpy>=1.0.1 from https://files.pythonhosted.org/packages/85/fc/7fa5d17daf77306840a4e84668a48ddff09e6bc09ba4e37e85ffc8e4faa3/contourpy-1.3.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata\n",
      "  Downloading contourpy-1.3.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (5.4 kB)\n",
      "Collecting cycler>=0.10 (from matplotlib->-r ../requirements.txt (line 5))\n",
      "  Obtaining dependency information for cycler>=0.10 from https://files.pythonhosted.org/packages/e7/05/c19819d5e3d95294a6f5947fb9b9629efb316b96de511b418c53d245aae6/cycler-0.12.1-py3-none-any.whl.metadata\n",
      "  Downloading cycler-0.12.1-py3-none-any.whl.metadata (3.8 kB)\n",
      "Collecting fonttools>=4.22.0 (from matplotlib->-r ../requirements.txt (line 5))\n",
      "  Obtaining dependency information for fonttools>=4.22.0 from https://files.pythonhosted.org/packages/41/b8/d5933559303a4ab18c799105f4c91ee0318cc95db4a2a09e300116625e7a/fonttools-4.57.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata\n",
      "  Downloading fonttools-4.57.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (102 kB)\n",
      "     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 102.5/102.5 kB 7.1 MB/s eta 0:00:00\n",
      "Collecting kiwisolver>=1.3.1 (from matplotlib->-r ../requirements.txt (line 5))\n",
      "  Obtaining dependency information for kiwisolver>=1.3.1 from https://files.pythonhosted.org/packages/3a/97/5edbed69a9d0caa2e4aa616ae7df8127e10f6586940aa683a496c2c280b9/kiwisolver-1.4.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata\n",
      "  Downloading kiwisolver-1.4.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (6.2 kB)\n",
      "Collecting pyparsing>=2.3.1 (from matplotlib->-r ../requirements.txt (line 5))\n",
      "  Obtaining dependency information for pyparsing>=2.3.1 from https://files.pythonhosted.org/packages/05/e7/df2285f3d08fee213f2d041540fa4fc9ca6c2d44cf36d3a035bf2a8d2bcc/pyparsing-3.2.3-py3-none-any.whl.metadata\n",
      "  Downloading pyparsing-3.2.3-py3-none-any.whl.metadata (5.0 kB)\n",
      "Requirement already satisfied: jinja2 in /opt/app-root/lib64/python3.11/site-packages (from altair<6,>=4.0->streamlit==1.42.0->-r ../requirements.txt (line 1)) (3.1.6)\n",
      "Requirement already satisfied: jsonschema>=3.0 in /opt/app-root/lib64/python3.11/site-packages (from altair<6,>=4.0->streamlit==1.42.0->-r ../requirements.txt (line 1)) (4.23.0)\n",
      "Collecting narwhals>=1.14.2 (from altair<6,>=4.0->streamlit==1.42.0->-r ../requirements.txt (line 1))\n",
      "  Obtaining dependency information for narwhals>=1.14.2 from https://files.pythonhosted.org/packages/41/c1/e9bc6b67c774e7c1f939c91ea535f18f7644fedc61b20d6baa861ad52b34/narwhals-1.33.0-py3-none-any.whl.metadata\n",
      "  Downloading narwhals-1.33.0-py3-none-any.whl.metadata (9.2 kB)\n",
      "Collecting gitdb<5,>=4.0.1 (from gitpython!=3.1.19,<4,>=3.0.7->streamlit==1.42.0->-r ../requirements.txt (line 1))\n",
      "  Obtaining dependency information for gitdb<5,>=4.0.1 from https://files.pythonhosted.org/packages/a0/61/5c78b91c3143ed5c14207f463aecfc8f9dbb5092fb2869baf37c273b2705/gitdb-4.0.12-py3-none-any.whl.metadata\n",
      "  Downloading gitdb-4.0.12-py3-none-any.whl.metadata (1.2 kB)\n",
      "Collecting llvmlite<0.45,>=0.44.0dev0 (from numba>=0.54->shap->-r ../requirements.txt (line 2))\n",
      "  Obtaining dependency information for llvmlite<0.45,>=0.44.0dev0 from https://files.pythonhosted.org/packages/99/fe/d030f1849ebb1f394bb3f7adad5e729b634fb100515594aca25c354ffc62/llvmlite-0.44.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata\n",
      "  Downloading llvmlite-0.44.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (4.8 kB)\n",
      "Requirement already satisfied: six>=1.5 in /opt/app-root/lib64/python3.11/site-packages (from python-dateutil>=2.8.2->pandas->-r ../requirements.txt (line 3)) (1.17.0)\n",
      "Requirement already satisfied: charset-normalizer<4,>=2 in /opt/app-root/lib64/python3.11/site-packages (from requests<3,>=2.27->streamlit==1.42.0->-r ../requirements.txt (line 1)) (3.4.1)\n",
      "Requirement already satisfied: idna<4,>=2.5 in /opt/app-root/lib64/python3.11/site-packages (from requests<3,>=2.27->streamlit==1.42.0->-r ../requirements.txt (line 1)) (3.10)\n",
      "Requirement already satisfied: urllib3<3,>=1.21.1 in /opt/app-root/lib64/python3.11/site-packages (from requests<3,>=2.27->streamlit==1.42.0->-r ../requirements.txt (line 1)) (2.3.0)\n",
      "Requirement already satisfied: certifi>=2017.4.17 in /opt/app-root/lib64/python3.11/site-packages (from requests<3,>=2.27->streamlit==1.42.0->-r ../requirements.txt (line 1)) (2025.1.31)\n",
      "Requirement already satisfied: markdown-it-py>=2.2.0 in /opt/app-root/lib64/python3.11/site-packages (from rich<14,>=10.14.0->streamlit==1.42.0->-r ../requirements.txt (line 1)) (3.0.0)\n",
      "Requirement already satisfied: pygments<3.0.0,>=2.13.0 in /opt/app-root/lib64/python3.11/site-packages (from rich<14,>=10.14.0->streamlit==1.42.0->-r ../requirements.txt (line 1)) (2.19.1)\n",
      "Collecting smmap<6,>=3.0.1 (from gitdb<5,>=4.0.1->gitpython!=3.1.19,<4,>=3.0.7->streamlit==1.42.0->-r ../requirements.txt (line 1))\n",
      "  Obtaining dependency information for smmap<6,>=3.0.1 from https://files.pythonhosted.org/packages/04/be/d09147ad1ec7934636ad912901c5fd7667e1c858e19d355237db0d0cd5e4/smmap-5.0.2-py3-none-any.whl.metadata\n",
      "  Downloading smmap-5.0.2-py3-none-any.whl.metadata (4.3 kB)\n",
      "Requirement already satisfied: MarkupSafe>=2.0 in /opt/app-root/lib64/python3.11/site-packages (from jinja2->altair<6,>=4.0->streamlit==1.42.0->-r ../requirements.txt (line 1)) (3.0.2)\n",
      "Requirement already satisfied: attrs>=22.2.0 in /opt/app-root/lib64/python3.11/site-packages (from jsonschema>=3.0->altair<6,>=4.0->streamlit==1.42.0->-r ../requirements.txt (line 1)) (25.3.0)\n",
      "Requirement already satisfied: jsonschema-specifications>=2023.03.6 in /opt/app-root/lib64/python3.11/site-packages (from jsonschema>=3.0->altair<6,>=4.0->streamlit==1.42.0->-r ../requirements.txt (line 1)) (2024.10.1)\n",
      "Requirement already satisfied: referencing>=0.28.4 in /opt/app-root/lib64/python3.11/site-packages (from jsonschema>=3.0->altair<6,>=4.0->streamlit==1.42.0->-r ../requirements.txt (line 1)) (0.36.2)\n",
      "Requirement already satisfied: rpds-py>=0.7.1 in /opt/app-root/lib64/python3.11/site-packages (from jsonschema>=3.0->altair<6,>=4.0->streamlit==1.42.0->-r ../requirements.txt (line 1)) (0.24.0)\n",
      "Requirement already satisfied: mdurl~=0.1 in /opt/app-root/lib64/python3.11/site-packages (from markdown-it-py>=2.2.0->rich<14,>=10.14.0->streamlit==1.42.0->-r ../requirements.txt (line 1)) (0.1.2)\n",
      "Downloading streamlit-1.42.0-py2.py3-none-any.whl (9.6 MB)\n",
      "   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 9.6/9.6 MB 11.2 MB/s eta 0:00:00\n",
      "Downloading shap-0.47.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (972 kB)\n",
      "   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 972.6/972.6 kB 13.8 MB/s eta 0:00:00\n",
      "Downloading slicer-0.0.8-py3-none-any.whl (15 kB)\n",
      "Downloading scikit_learn-1.6.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (13.5 MB)\n",
      "   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 13.5/13.5 MB 5.7 MB/s eta 0:00:00\n",
      "Downloading matplotlib-3.10.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (8.6 MB)\n",
      "   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 8.6/8.6 MB 3.0 MB/s eta 0:00:00\n",
      "Downloading altair-5.5.0-py3-none-any.whl (731 kB)\n",
      "   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 731.2/731.2 kB 5.8 MB/s eta 0:00:00\n",
      "Downloading blinker-1.9.0-py3-none-any.whl (8.5 kB)\n",
      "Downloading contourpy-1.3.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (326 kB)\n",
      "   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 326.2/326.2 kB 5.6 MB/s eta 0:00:00\n",
      "Downloading cycler-0.12.1-py3-none-any.whl (8.3 kB)\n",
      "Downloading fonttools-4.57.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (4.9 MB)\n",
      "   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 4.9/4.9 MB 6.8 MB/s eta 0:00:00\n",
      "Downloading GitPython-3.1.44-py3-none-any.whl (207 kB)\n",
      "   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 207.6/207.6 kB 21.0 MB/s eta 0:00:00\n",
      "Downloading joblib-1.4.2-py3-none-any.whl (301 kB)\n",
      "   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 301.8/301.8 kB 15.0 MB/s eta 0:00:00\n",
      "Downloading kiwisolver-1.4.8-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (1.4 MB)\n",
      "   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1.4/1.4 MB 6.8 MB/s eta 0:00:00\n",
      "Downloading numba-0.61.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl (3.8 MB)\n",
      "   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 3.8/3.8 MB 9.3 MB/s eta 0:00:00\n",
      "Downloading pillow-11.1.0-cp311-cp311-manylinux_2_28_x86_64.whl (4.5 MB)\n",
      "   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 4.5/4.5 MB 9.8 MB/s eta 0:00:00\n",
      "Downloading pydeck-0.9.1-py2.py3-none-any.whl (6.9 MB)\n",
      "   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 6.9/6.9 MB 9.4 MB/s eta 0:00:00\n",
      "Downloading pyparsing-3.2.3-py3-none-any.whl (111 kB)\n",
      "   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 111.1/111.1 kB 12.0 MB/s eta 0:00:00\n",
      "Downloading scipy-1.15.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (37.6 MB)\n",
      "   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 37.6/37.6 MB 3.5 MB/s eta 0:00:00\n",
      "Downloading threadpoolctl-3.6.0-py3-none-any.whl (18 kB)\n",
      "Downloading tornado-6.4.2-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (437 kB)\n",
      "   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 437.2/437.2 kB 8.4 MB/s eta 0:00:00\n",
      "Downloading watchdog-6.0.0-py3-none-manylinux2014_x86_64.whl (79 kB)\n",
      "   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 79.1/79.1 kB 5.8 MB/s eta 0:00:00\n",
      "Downloading gitdb-4.0.12-py3-none-any.whl (62 kB)\n",
      "   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 62.8/62.8 kB 9.3 MB/s eta 0:00:00\n",
      "Downloading llvmlite-0.44.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (42.4 MB)\n",
      "   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 42.4/42.4 MB 7.3 MB/s eta 0:00:00\n",
      "Downloading narwhals-1.33.0-py3-none-any.whl (322 kB)\n",
      "   ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 322.8/322.8 kB 5.6 MB/s eta 0:00:00\n",
      "Downloading smmap-5.0.2-py3-none-any.whl (24 kB)\n",
      "Installing collected packages: watchdog, tornado, threadpoolctl, smmap, slicer, scipy, pyparsing, pillow, narwhals, llvmlite, kiwisolver, joblib, fonttools, cycler, contourpy, blinker, scikit-learn, pydeck, numba, matplotlib, gitdb, shap, gitpython, altair, streamlit\n",
      "Successfully installed altair-5.5.0 blinker-1.9.0 contourpy-1.3.1 cycler-0.12.1 fonttools-4.57.0 gitdb-4.0.12 gitpython-3.1.44 joblib-1.4.2 kiwisolver-1.4.8 llvmlite-0.44.0 matplotlib-3.10.1 narwhals-1.33.0 numba-0.61.0 pillow-11.1.0 pydeck-0.9.1 pyparsing-3.2.3 scikit-learn-1.6.1 scipy-1.15.2 shap-0.47.1 slicer-0.0.8 smmap-5.0.2 streamlit-1.42.0 threadpoolctl-3.6.0 tornado-6.4.2 watchdog-6.0.0\n",
      "\n",
      "[notice] A new release of pip is available: 23.2.1 -> 25.0.1\n",
      "[notice] To update, run: pip install --upgrade pip\n",
      "Defaulted container \"online\" out of: online, feast-init (init)\n",
      "Loan rejected!\n"
     ]
    }
   ],
   "source": [
    "!kubectl create job --from=cronjob/feast-example feast-example-demo\n",
    "!kubectl wait --for=condition=complete --timeout=8m job/feast-example-demo\n",
    "!kubectl logs job/feast-example-demo --all-containers=true"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Interactive demo (using Streamlit)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In a new terminal, run the following command and leave it active.\n",
    "\n",
    "```bash\n",
    "$ kubectl port-forward deploy/feast-example 8501:8501\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Start the Streamlit application"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Collecting usage statistics. To deactivate, set browser.gatherUsageStats to false.\n",
      "\u001b[0m\n",
      "\u001b[0m\n",
      "\u001b[34m\u001b[1m  You can now view your Streamlit app in your browser.\u001b[0m\n",
      "\u001b[0m\n",
      "\u001b[34m  Local URL: \u001b[0m\u001b[1mhttp://localhost:8501\u001b[0m\n",
      "\u001b[34m  Network URL: \u001b[0m\u001b[1mhttp://10.42.0.11:8501\u001b[0m\n",
      "\u001b[34m  External URL: \u001b[0m\u001b[1mhttp://23.112.66.217:8501\u001b[0m\n",
      "\u001b[0m\n"
     ]
    }
   ],
   "source": [
    "!kubectl exec deploy/feast-example -itc online -- bash -c 'cd ../ && streamlit run --server.port 8501 streamlit_app.py'"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Then navigate to the local URL on which Streamlit is being served.\n",
    "\n",
    "http://localhost:8501"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
